home *** CD-ROM | disk | FTP | other *** search
/ Power Programmierung 2 / Power-Programmierung CD 2 (Tewi)(1994).iso / gnu / gnulib / dkbtrace / pbmplus / source / ppm / ppmdithe.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-10  |  6.6 KB  |  256 lines

  1. /* ppmdither.c - Ordered dithering of a color ppm file to a specified number
  2. **               of primary shades.
  3. **
  4. ** Copyright (C) 1991 by Christos Zoulas.
  5. **
  6. ** Permission to use, copy, modify, and distribute this software and its
  7. ** documentation for any purpose and without fee is hereby granted, provided
  8. ** that the above copyright notice appear in all copies and that both that
  9. ** copyright notice and this permission notice appear in supporting
  10. ** documentation.  This software is provided "as is" without express or
  11. ** implied warranty.
  12. */
  13.  
  14. #include "ppm.h"
  15.  
  16. #define NC 256            /* Total number of colors        */
  17. #define NS 256            /* Max number of shades in primary    */
  18.  
  19. typedef unsigned char ubyte;
  20.  
  21. static int dith_nr  =   5;    /* number of red shades            */
  22. static int dith_ng  =   9;    /* number of green shades        */
  23. static int dith_nb  =   5;    /* number of blue shades        */
  24. static int dith_nc  = 225;    /* total number of colors 5 x 9 x 5    */
  25. static int dith_dim =   4;    /* dimension of the dither matrix    */
  26. static int dith_dm2 =  16;    /* dim square                */
  27. static int **dith_mat;         /* the dithering matrix            */
  28.  
  29. /* COLOR():
  30.  *    returns the index in the color table for the
  31.  *      r, g, b values specified.
  32.  */
  33. #define COLOR(r,g,b) (((r) * dith_ng + (g)) * dith_nb + (b))
  34.  
  35. /* LEVELS():
  36.  *    Returns the total number of levels after dithering.
  37.  */
  38. #define LEVELS(s)     (dith_dm2 * ((s) - 1) + 1)
  39.  
  40. /* DITHER():
  41.  *    Returns the dithered color for a single primary.
  42.  *      p = the input pixel
  43.  *      d = entry in the dither matrix
  44.  *      s = the number of levels of the primary
  45.  *
  46.  */
  47. #define DITHER(p,d,s) ((ubyte) ((LEVELS(s) * (p) + (d)) / (dith_dm2 * NS)))
  48.  
  49.  
  50. /* dith_value():
  51.  *    Return the value of a dither matrix of size x size at x, y 
  52.  *    [graphics gems, p. 714]
  53.  */
  54. static int
  55. dith_value(y, x, size)
  56. int y, x, size;
  57. {
  58.     register int d;
  59.  
  60.     /*
  61.      * Think of d as the density. At every iteration, d is shifted
  62.      * left one and a new bit is put in the low bit based on x and y.
  63.      * If x is odd and y is even, or visa versa, then a bit is shifted in.
  64.      * This generates the checkerboard pattern seen in dithering.
  65.      * This quantity is shifted again and the low bit of y is added in.
  66.      * This whole thing interleaves a checkerboard pattern and y's bits
  67.      * which is what you want.
  68.      */
  69.     for (d = 0; size-- > 0; x >>= 1, y >>= 1)
  70.     d = (d << 2) | (((x & 1) ^ (y & 1)) << 1) | (y & 1);
  71.     return(d);
  72. } /* end dith_value */
  73.  
  74.  
  75. /* dith_matrix():
  76.  *    Form the dithering matrix for the dimension specified
  77.  *    (Scaled by NS)
  78.  */
  79. static void
  80. dith_matrix(dim)
  81. int dim;
  82. {
  83.     int x, y, *dat;
  84.  
  85.     dith_dim = (1 << dim);
  86.     dith_dm2 = dith_dim * dith_dim;
  87.  
  88.     dith_mat = (int **) malloc((dith_dim * sizeof(int *)) + /* pointers */
  89.                    (dith_dm2 * sizeof(int)));   /* data */
  90.  
  91.     if (dith_mat == NULL) 
  92.     pm_error("out of memory");
  93.  
  94.     dat =  (int *) &dith_mat[dith_dim];
  95.     for (y = 0; y < dith_dim; y++)
  96.     dith_mat[y] = &dat[y * dith_dim];
  97.  
  98.     for (y = 0; y < dith_dim; y++) {
  99.     for (x = 0; x < dith_dim; x++) {
  100.          dith_mat[y][x] = NS * dith_value(y, x, dim);
  101. #ifdef DEBUG
  102.          (void) fprintf(stderr, "%4d ", dith_mat[y][x]);
  103. #endif
  104.     }
  105. #ifdef DEBUG
  106.     (void) fprintf(stderr, "\n");
  107. #endif
  108.     }
  109. } /* end dith_matrix */
  110.  
  111.     
  112. /* dith_setup():
  113.  *    Setup the dithering parameters, lookup table and dithering matrix
  114.  */
  115. void
  116. dith_setup(dim, nr, ng, nb, ptab)
  117. int dim, nr, ng, nb;
  118. pixel *ptab;
  119. {
  120.     register int r, g, b, i;
  121.  
  122.     dith_nr  = nr;
  123.     dith_ng  = ng;
  124.     dith_nb  = nb;
  125.     dith_nc  = nr * ng * nb;
  126.  
  127.     if (dith_nc > NC)
  128.     pm_error("too many shades %d, max %d", dith_nc, NC);
  129.     if (dith_nr < 2) 
  130.     pm_error("too few shades for red, minimum of 2");
  131.     if (dith_ng < 2) 
  132.     pm_error("too few shades for green, minimum of 2");
  133.     if (dith_nb < 2) 
  134.     pm_error("too few shades for blue, minimum of 2");
  135.     
  136.     for (r = 0; r < dith_nr; r++) 
  137.     for (g = 0; g < dith_ng; g++) 
  138.         for (b = 0; b < dith_nb; b++) {
  139.         i = COLOR(r,g,b);
  140.         PPM_ASSIGN(ptab[COLOR(r,g,b)], 
  141.                    (r * (NC-1) / (dith_nr - 1)),
  142.                    (g * (NC-1) / (dith_ng - 1)),
  143.                    (b * (NC-1) / (dith_nb - 1)));
  144.         }
  145.     
  146.     dith_matrix(dim);
  147. } /* end dith_setup */
  148.  
  149.  
  150. /* dith_color():
  151.  *  Return the closest color index for the one we ask
  152.  */
  153. int
  154. dith_color(r, g, b)
  155. float r, g, b;
  156. {
  157.     int rr, gg, bb;
  158.  
  159.     rr = r * (dith_nr - 1);
  160.     gg = g * (dith_ng - 1);
  161.     bb = b * (dith_nb - 1);
  162.     return((int) COLOR(rr, gg, bb));
  163. } /* end dith_color */
  164.  
  165.  
  166. /* dith_dither():
  167.  *  Dither height scanlines at a time
  168.  */
  169. void
  170. dith_dither(w, h, t, i, o)
  171. int w, h;
  172. register pixel *t;
  173. register pixel *i;
  174. register pixel *o;
  175. {
  176.     int y, dm = (dith_dim - 1);
  177.     register int x, d;
  178.     register int *m;
  179.  
  180.     for (y = 0; y < h; y++)
  181.     for (m = dith_mat[y & dm], x = w; --x >= 0;i++) {
  182.         d = m[x & dm];
  183.         *o++ = t[COLOR(DITHER(PPM_GETR(*i), d, dith_nr), 
  184.                    DITHER(PPM_GETG(*i), d, dith_ng), 
  185.                    DITHER(PPM_GETB(*i), d, dith_nb))];
  186.     }
  187. } /* end dith_dither */
  188.  
  189.  
  190. void
  191. main( argc, argv )
  192.     int argc;
  193.     char* argv[];
  194.     {
  195.     FILE* ifp;
  196.     pixel ptab[256];
  197.     pixel **ipixels, **opixels;
  198.     int cols, rows;
  199.     pixval maxval;
  200.     int argn;
  201.     char* usage = 
  202.     "[-dim <num>] [-red <num>] [-green <num>] [-blue <num>] [pbmfile]";
  203.  
  204.     ppm_init( &argc, argv );
  205.  
  206.     argn = 1;
  207.  
  208.     while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  209.     {
  210.     if ( pm_keymatch( argv[argn], "-dim", 1) &&  argn + 1 < argc ) {
  211.         argn++;
  212.         if (sscanf(argv[argn], "%d", &dith_dim) != 1)
  213.         pm_usage( usage );
  214.     }
  215.     else if ( pm_keymatch( argv[argn], "-red", 1 ) && argn + 1 < argc ) {
  216.         argn++;
  217.         if (sscanf(argv[argn], "%d", &dith_nr) != 1)
  218.         pm_usage( usage );
  219.     }
  220.     else if ( pm_keymatch( argv[argn], "-green", 1 ) && argn + 1 < argc ) {
  221.         argn++;
  222.         if (sscanf(argv[argn], "%d", &dith_ng) != 1)
  223.         pm_usage( usage );
  224.     }
  225.     else if ( pm_keymatch( argv[argn], "-blue", 1 ) && argn + 1 < argc ) {
  226.         argn++;
  227.         if (sscanf(argv[argn], "%d", &dith_nb) != 1)
  228.         pm_usage( usage );
  229.     }
  230.     else
  231.         pm_usage( usage );
  232.     ++argn;
  233.     }
  234.  
  235.     if ( argn != argc )
  236.     {
  237.     ifp = pm_openr( argv[argn] );
  238.     ++argn;
  239.     }
  240.     else
  241.     ifp = stdin;
  242.  
  243.     if ( argn != argc )
  244.     pm_usage( usage );
  245.  
  246.     ipixels = ppm_readppm( ifp, &cols, &rows, &maxval );
  247.     pm_close( ifp );
  248.     opixels = ppm_allocarray(cols, rows);
  249.     maxval = 255;
  250.     dith_setup(dith_dim, dith_nr, dith_ng, dith_nb, ptab);
  251.     dith_dither(cols, rows, ptab, &ipixels[0][0], &opixels[0][0]);
  252.     ppm_writeppm(stdout, opixels, cols, rows, maxval, 0);
  253.     pm_close(stdout);
  254.     exit(0);
  255. }
  256.